#include "UICommon.h"
#include "StringTools.h"
#include "AppDelegate.h"

using namespace strtool;

UICDropdownList * UICDropdownList::create(Size size, Color4B bgcolor, Color4B fgcolor, TextHAlignment align)
{
	auto ddl = new UICDropdownList();
	ddl->size = size;
	ddl->bgcolor = bgcolor;
	ddl->fgcolor = fgcolor;

	ddl->hvcolor = Color4B(.75f * bgcolor.r + 32, .75f * bgcolor.g + 32, .75f * bgcolor.b + 32, bgcolor.a);
	ddl->align = align;

	ddl->cliplayer = LayerColor::create(bgcolor, size.width, size.height);
	UI::setNodeAnch(ddl->cliplayer, ANCH_BL);
	ddl->setStencil(ddl->cliplayer);
	ddl->setContentSize(size);
	ddl->itemspace = LayerColor::create(Color4B(0, 0, 0, 0), size.width, size.height);
	UI::setNodeAnch(ddl->itemspace, ANCH_BL);
	ddl->addChild(ddl->itemspace);

	return ddl;
}

void UICDropdownList::addItem(string text, int tag)
{
	auto item = LayerColor::create(bgcolor, size.width, size.height);
	UI::setNodeAnch(item, ANCH_BL);
	item->setPosition(0, size.height*(items.size() + .1f));
	item->setTag(tag);

	auto itemtext = Label::createWithTTF(text, FONTA, size.height*.8f, Size::ZERO, align, TextVAlignment::CENTER);
	UI::setNodeAnch(itemtext, ANCH_BL);
	itemtext->setTextColor(fgcolor);
	itemtext->setWidth(size.width);
	itemtext->setHeight(size.height);
	item->addChild(itemtext);

	itemspace->addChild(item);
	items.push_back(item);
	itemspace->changeHeight(size.height*items.size());
	itemcount++;
}

int UICDropdownList::getHoverIndex(float posy)
{
	int index = posy / size.height;
	return index;
}

int UICDropdownList::getSelectedTag()
{
	if (selectedindex >= 0) return items[selectedindex]->getTag();
	return 0;
}

void UICDropdownList::setSelectedIndex(int index)
{
	itemspace->setAnchorPoint(Vec2(0, index*size.height / itemspace->getContentSize().height - itemspace->getAnchorPoint().y));
	selectedindex = index;
}

void UICDropdownList::onMouseMove(Event * e)
{
	if (isMouseHoverNode(isExpanded ? (Node*)itemspace : this, e))
	{
		auto hi = getHoverIndex(getMouseLocInNode(itemspace, e).y);
		if ((hoverindex != hi) && (hi >= 0) && (hi < itemcount))
		{
			if (hoverindex >= 0)
			{
				items[hoverindex]->stopAllActionsByTag(1);
				auto lact = TintTo::create(.1f, Color3B(bgcolor));
				lact->setTag(1);
				items[hoverindex]->runAction(lact);
			}
			items[hi]->stopAllActionsByTag(1);
			auto hact = TintTo::create(.1f, Color3B(hvcolor));
			hact->setTag(1);
			items[hi]->runAction(hact);
			hoverindex = hi;
		}
	}
	else if (hoverindex >= 0 && hoverindex < itemcount)
	{
		items[hoverindex]->stopAllActionsByTag(1);
		auto lact = TintTo::create(.1f, Color3B(bgcolor));
		lact->setTag(1);
		items[hoverindex]->runAction(lact);
		hoverindex = -1;
	}
}

void UICDropdownList::onMouseDown(Event * e)
{
	if (mouseKey == MOUSELEFT)
	{
		if (!isExpanded)
		{
			if (mouseStatus == MOUSEHOVER || mouseStatus == MOUSEENTER)
			{
				isExpanded = true;
				UI::moveEventFlagUp();
				moveEventFlagUp();
				//zorder = getZOrder();
				zorder = getLocalZOrder();
				setLocalZOrder(INT_MAX);
				thread([&]
				{
					float stepa = 0;
					auto stepy = (-selectedindex*size.height - cliplayer->getPositionY()) / 10;
					auto steph = (size.height*items.size() - cliplayer->getContentSize().height) / 10;
					auto spaceheight = itemspace->getContentSize().height;
					auto worldposy = convertToWorldSpace(Vec2::ZERO).y;
					if (worldposy < spaceheight)
					{
						stepa = -itemspace->getAnchorPoint().y / 10;
						stepy = -cliplayer->getPositionY() / 10;
					}
					else if (worldposy > frameSize.height - spaceheight)
					{
						stepa = ((itemcount - 1)*size.height / spaceheight - itemspace->getAnchorPoint().y) / 10;
						stepy = (-(itemcount - 1)*size.height - cliplayer->getPositionY()) / 10;
					}
					for (int i = 0; i < 10 && isExpanded; i++)
					{
						itemspace->setAnchorPoint(Vec2(0, itemspace->getAnchorPoint().y + stepa));
						cliplayer->setPositionY(cliplayer->getPositionY() + stepy);
						cliplayer->changeHeight(cliplayer->getContentSize().height + steph);
						this_thread::sleep_for(chrono::milliseconds(15));
					}
				}
				).detach();
			}
		}
		else
		{
			if (isMouseHoverArea(itemspace->convertToWorldSpace(Vec2::ZERO), itemspace->getContentSize(), e) && selectedindex != hoverindex)
			{
				selectedindex = hoverindex;
				if (selectedindex >= 0)	runAdditionalEventAction(MOUSEDOWN);
			}
			isExpanded = false;
			UI::moveEventFlagDown();
			moveEventFlagDown();
			setLocalZOrder(zorder);
			auto spaceheight = itemspace->getContentSize().height;
			thread([&]
			{
				auto stepa = (selectedindex*size.height / spaceheight - itemspace->getAnchorPoint().y) / 10;
				auto stepy = (0 - cliplayer->getPositionY()) / 10;
				auto steph = (size.height - cliplayer->getContentSize().height) / 10;
				for (int i = 0; i < 10 && !isExpanded; i++)
				{
					itemspace->setAnchorPoint(Vec2(0, itemspace->getAnchorPoint().y + stepa));
					cliplayer->setPositionY(cliplayer->getPositionY() + stepy);
					cliplayer->changeHeight(cliplayer->getContentSize().height + steph);
					this_thread::sleep_for(chrono::milliseconds(15));
				}
			}
			).detach();
		}
	}
}

UICSliderBar * UICSliderBar::create(Size size, Color4B bgcolor, Color4B fgcolor, float minval, float maxval, float steppingval, float defvalue, int valdecimal)
{
	auto sldb = new UICSliderBar();
	sldb->initWithColor(bgcolor);
	sldb->size = size;
	sldb->bgcolor = bgcolor;
	sldb->fgcolor = fgcolor;
	sldb->minval = minval;
	sldb->maxval = maxval;
	sldb->steppingval = steppingval;
	sldb->defvalue = defvalue;
	sldb->valdecimal = valdecimal;
	sldb->changeWidthAndHeight(size.width, size.height);

	auto borderclip = ClippingNode::create();
	auto stencil = LayerColor::create(Color4B::BLACK, size.width*.8f - 6, size.height - 6);
	stencil->setPosition(3, 3);
	borderclip->setStencil(stencil);
	borderclip->setInverted(true);

	auto borderlayer = LayerColor::create(sldb->fgcolor, size.width*.8f, size.height);
	borderclip->addChild(borderlayer);
	sldb->addChild(borderclip);
	sldb->ptrminx = size.height;
	sldb->ptrmaxx = size.width*.8f - sldb->ptrminx;
	sldb->ptrspace = sldb->ptrmaxx - sldb->ptrminx;

	sldb->pointer = LayerColor::create(sldb->fgcolor, size.height*.5f, size.height*.5f);
	UI::setNodeAnch(sldb->pointer, ANCH_M);
	sldb->pointer->setPosition(size.width*.5f, size.height*.5f);
	sldb->pointer->setRotation(45);
	sldb->addChild(sldb->pointer);
	auto ptrmoveby = sldb->pointer->getContentSize().height * 2;
	auto ptl = Label::createWithTTF("<", FONTA, size.height*.5f);
	ptl->setTextColor(sldb->fgcolor);
	UI::setNodeAnch(ptl, ANCH_M);
	ptl->setRotation(-45);
	ptl->setLocalZOrder(sldb->pointer->getLocalZOrder() - 1);
	ptl->runAction(
		RepeatForever::create(
			Sequence::create(
				FadeIn::create(0),
				MoveTo::create(0, Vec2(sldb->pointer->getAnchorPointInPoints())),
				Spawn::create(
					MoveBy::create(.5f, Vec2(-ptrmoveby, -ptrmoveby)),
					FadeOut::create(.5f),
					NULL
				),
				DelayTime::create(.5f),
				NULL
			)
		)
	);
	sldb->pointer->addChild(ptl);
	auto ptr = Label::createWithTTF(">", FONTA, size.height*.5f);
	ptr->setTextColor(sldb->fgcolor);
	UI::setNodeAnch(ptr, ANCH_M);
	ptr->setRotation(-45);
	ptr->setLocalZOrder(sldb->pointer->getLocalZOrder() - 1);
	ptr->runAction(
		RepeatForever::create(
			Sequence::create(
				FadeIn::create(0),
				MoveTo::create(0, Vec2(sldb->pointer->getAnchorPointInPoints())),
				Spawn::create(
					MoveBy::create(.5f, Vec2(ptrmoveby, ptrmoveby)),
					FadeOut::create(.5f),
					NULL
				),
				DelayTime::create(.5f),
				NULL
			)
		)
	);
	sldb->pointer->addChild(ptr);

	sldb->valuetext = Label::createWithTTF("", FONTA, size.height*.8f, Size::ZERO, TextHAlignment::CENTER, TextVAlignment::CENTER);
	UI::setNodeAnch(sldb->valuetext, ANCH_BL);
	sldb->valuetext->setPositionX(size.width*.8f);
	sldb->valuetext->setWidth(size.width*.2f);
	sldb->valuetext->setHeight(size.height);
	sldb->valuetext->setTextColor(fgcolor);
	sldb->addChild(sldb->valuetext);

	sldb->setValue(defvalue, true);

	return sldb;
}

float UICSliderBar::getValue()
{
	return value;
}

void UICSliderBar::setValue(float newvalue, bool setptrloc)
{
	if (newvalue >= minval && newvalue <= maxval)
	{
		value = newvalue;
		valuetext->setString(valdecimal > 0 ? dou2str(newvalue, valdecimal) : int2str(newvalue));
		if (setptrloc) pointer->setPositionX(((newvalue - minval) / (maxval - minval))*(ptrmaxx - ptrminx) + ptrminx);
		if (onValueChangeAction) onValueChangeAction();
	}
}

void UICSliderBar::setValueByLoc(float locx, bool setptrloc)
{
	locx = sorbPtrInRange(locx);
	float valloc = ((locx - ptrminx) / (ptrmaxx - ptrminx))*(maxval - minval);
	int steps = valloc / steppingval + 0.5f;
	float val = minval + steppingval*steps;
	setValue(val, setptrloc);
}

void UICSliderBar::setOnValueChangeAction(function<void()> func)
{
	onValueChangeAction = func;
}

float UICSliderBar::sorbPtrInRange(float x)
{
	if (x > ptrmaxx) x = ptrmaxx;
	else if (x < ptrminx) x = ptrminx;
	return x;
}

void UICSliderBar::setValueByMouse(Event * e)
{
	auto mouselocx = sorbPtrInRange(getMouseLocInNode(this, e).x);
	setValueByLoc(mouselocx);
	pointer->setPositionX(mouselocx);
}

void UICSliderBar::onMouseMove(Event * e)
{
	if (mouseStatus == MOUSEENTER && !isdragging)
	{
		pointer->runAction(TintTo::create(.1f, Color3B(.67f * fgcolor.r + 42.67f, .67f * fgcolor.g + 42.67f, .67f * fgcolor.b + 42.67f)));
	}
	else if (mouseStatus == MOUSELEAVE && !isdragging)
	{
		pointer->runAction(TintTo::create(.1f, Color3B(fgcolor)));
	}
	if (isdragging)
	{
		setValueByMouse(e);
	}
}

void UICSliderBar::onMouseDown(Event * e)
{
	if ((mouseStatus == MOUSEHOVER || mouseStatus == MOUSEENTER) && mouseKey == MOUSELEFT)
	{
		setEventFlag(UI::moveEventFlagUp());
		isdragging = true;
		setValueByMouse(e);
	}
}

void UICSliderBar::onMouseUp(Event * e)
{
	if (mouseKey == MOUSELEFT && isdragging)
	{
		setEventFlag(UI::moveEventFlagDown());
		isdragging = false;
		if (mouseStatus == MOUSEOUTER || mouseStatus == MOUSELEAVE) pointer->runAction(TintTo::create(.1f, Color3B(fgcolor)));
		runAdditionalEventAction(MOUSEUP);
	}
}

UICSwitchOnOff * UICSwitchOnOff::create(Size size, Color4B bgcolor, Color4B fgcolor, bool defison, string texton, string textoff, TextHAlignment align)
{
	auto sw = new UICSwitchOnOff();
	sw->size = size;
	sw->bgcolor = bgcolor;
	sw->fgcolor = fgcolor;
	sw->hvcolor = Color4B(.75f * bgcolor.r + 32, .75f * bgcolor.g + 32, .75f * bgcolor.b + 32, bgcolor.a);
	//sw->isOn = defison;
	sw->align = align;

	auto cliplayer = LayerColor::create(bgcolor, size.width, size.height);
	UI::setNodeAnch(cliplayer, ANCH_BL);
	sw->setStencil(cliplayer);
	sw->setContentSize(size);

	sw->itemspace = LayerColor::create(bgcolor, size.width, size.height * 2);
	UI::setNodeAnch(sw->itemspace, ANCH_BL);
	auto lon = Label::createWithTTF(texton, FONTA, size.height*.8f, Size::ZERO, align, TextVAlignment::CENTER);
	lon->setTextColor(fgcolor);
	UI::setNodeAnch(lon, ANCH_BL);
	lon->setWidth(size.width);
	lon->setHeight(size.height);
	lon->setPositionY(size.height);
	sw->itemspace->addChild(lon);
	auto loff = Label::createWithTTF(textoff, FONTA, size.height*.8f, Size::ZERO, align, TextVAlignment::CENTER);
	loff->setTextColor(fgcolor);
	UI::setNodeAnch(loff, ANCH_BL);
	loff->setWidth(size.width);
	loff->setHeight(size.height);
	sw->itemspace->addChild(loff);
	sw->addChild(sw->itemspace);

	sw->setStatus(defison);
	return sw;
}

void UICSwitchOnOff::toggleStatus()
{
	isOn = !isOn;
	updateUI();
}

void UICSwitchOnOff::setStatus(bool isStatusOn)
{
	isOn = isStatusOn;
	updateUI();
}

void UICSwitchOnOff::updateUI()
{
	if (isOn) itemspace->runAction(MoveTo::create(.1f, Vec2(0, -size.height)));
	else itemspace->runAction(MoveTo::create(.1f, Vec2(0, 0)));
}

bool UICSwitchOnOff::getStatus()
{
	return isOn;
}

void UICSwitchOnOff::onMouseMove(Event * e)
{
	if (mouseStatus == MOUSEENTER) itemspace->runAction(TintTo::create(.1f, Color3B(hvcolor)));
	else if (mouseStatus == MOUSELEAVE) itemspace->runAction(TintTo::create(.1f, Color3B(bgcolor)));
}

void UICSwitchOnOff::onMouseDown(Event * e)
{
	if (mouseStatus == MOUSEENTER || mouseStatus == MOUSEHOVER)
	{
		toggleStatus();
		runAdditionalEventAction(MOUSEDOWN);
	}
}

UICButton * UICButton::create(Size size, string text, Color4B bgcolor, Color4B fgcolor, TextHAlignment align)
{
	auto btn = new UICButton();
	btn->initWithColor(bgcolor);
	btn->changeWidthAndHeight(size.width, size.height);

	btn->size = size;
	btn->bgcolor = bgcolor;
	btn->fgcolor = fgcolor;
	btn->hvcolor = Color4B(.75f * bgcolor.r + 32, .75f * bgcolor.g + 32, .75f * bgcolor.b + 32, bgcolor.a);

	btn->underline = LayerColor::create(fgcolor, size.width, size.height*.1f);
	UI::setNodeAnch(btn->underline, ANCH_BL);
	btn->addChild(btn->underline);

	btn->text = Label::createWithTTF(text, FONTA, size.width > size.height ? size.height*.8f : size.width*.8f, Size::ZERO, align, TextVAlignment::CENTER);
	btn->text->setColor(Color3B(fgcolor));
	btn->text->setLineHeight(size.width > size.height ? size.height : size.width);
	switch (align)
	{
		case cocos2d::TextHAlignment::LEFT:
			UI::setNodeAnch(btn->text, ANCH_BL);
			btn->text->setPosition(0, size.height);
			break;
		case cocos2d::TextHAlignment::CENTER:
			UI::setNodeAnch(btn->text, ANCH_M);
			btn->text->setPosition(size.width*.5f, size.height*.5f);
			break;
		case cocos2d::TextHAlignment::RIGHT:
			UI::setNodeAnch(btn->text, ANCH_TR);
			btn->text->setPosition(size.width, size.height);
			break;
		default:
			break;
	}
	btn->addChild(btn->text);

	return btn;
}

void UICButton::setActiveStat(bool active)
{
	isActive = active;
	if (active)
	{
		underline->runAction(ScaleTo::create(.1f, 1, 2));
		auto action = RepeatForever::create(
			Sequence::create(
				FadeTo::create(.05f, 128),
				FadeTo::create(.05f, 255),
				NULL
			)
		);
		action->setTag(1);
		underline->runAction(action);
	}
	else
	{
		underline->stopActionByTag(1);
		underline->runAction(FadeTo::create(.05f, 255));
		underline->runAction(ScaleTo::create(.1f, 1, 1));
	}
}

void UICButton::toggleActiveStat()
{
	setActiveStat(!isActive);
}

bool UICButton::getActiveStat()
{
	return isActive;
}

void UICButton::setTag(int tagvalue)
{
	tag = tagvalue;
}

int UICButton::getTag()
{
	return tag;
}

void UICButton::setDirection(DIRECTION direction)
{
	switch (direction)
	{
		case UICButton::UP:
			text->setRotation(0);
			underline->setRotation(0);
			underline->setPosition(0, 0);
			underline->changeWidthAndHeight(size.width, size.height*.1f);
			break;
		case UICButton::LEFT:
			text->setRotation(-90);
			underline->setRotation(-90);
			underline->setPosition(size.width, 0);
			underline->changeWidthAndHeight(size.height, size.width*.1f);
			break;
		case UICButton::RIGHT:
			text->setRotation(90);
			underline->setRotation(90);
			underline->setPosition(0, size.height);
			underline->changeWidthAndHeight(size.height, size.width*.1f);
			break;
		default:
			break;
	}
}

void UICButton::onMouseMove(Event * e)
{
	if (!isActive)
	{
		if (mouseStatus == MOUSEENTER)
		{
			underline->runAction(ScaleTo::create(.1f, 1, 2));
		}
		else if (mouseStatus == MOUSELEAVE)
		{
			underline->runAction(ScaleTo::create(.1f, 1, 1));
		}
	}
}

void UICButton::onMouseDown(Event * e)
{
	if ((mouseStatus == MOUSEENTER || mouseStatus == MOUSEHOVER) && mouseKey == MOUSELEFT) runAdditionalEventAction(MOUSEDOWN);
}
